#ifndef CHAIN_OF_RESP_HPP
#define CHAIN_OF_RESP_HPP

#include <iostream>
#include <string>
#include <memory>
#include <filesystem>
#include <fstream>
#include <ctime>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#define PATH_DEFAULT "./tmp/"
#define FILE_DEFAULT "text.log"
#define EXIT_ERROR(m) \
    do                \
    {                 \
        perror(m);    \
        exit(1);      \
    } while (0)

class HandlerText
{

public:
    virtual void Excute(const std::string &msg) = 0;
    void SetNext(const std::shared_ptr<HandlerText> &next)
    {
        _next = next;
    }
    void Disable() { _status = false; }
    void Enable() { _status = true; }
    bool Stat() { return _status; }

protected:
    std::shared_ptr<HandlerText> _next;

private:
    bool _status = true;
};

// 格式化内容，拼接上时间戳和进程pid
class HandlerTextFormat : public HandlerText
{
public:
    HandlerTextFormat(const std::string &pathname, const std::string &filename)
        : _pathname(pathname), _filename(filename)
    {
    }
    ~HandlerTextFormat()
    {
    }
    virtual void Excute(const std::string &msg)
    {
        std::string format = msg + "\n";
        // 动态裁剪
        if (Stat())
        {
            std::cout << "step 1:文本格式化" << std::endl;
            std::string cur = std::to_string((int)time(nullptr));
            format += "时间戳:" + cur + " 进程pid:" + std::to_string(getpid()) + "\n";
        }
        else
        {
            std::cout << "step 1:文本格式化(已禁用)" << std::endl;
        }
        if (_next)
        {
            _next->Excute(format);
        }
        else
        {
            std::cout << "责任链终止在HandlerTextFormat" << std::endl;
        }
    }

private:
    std::string _pathname;
    std::string _filename;
};

// 把msg写到文件中
class HandlerTextSaveFile : public HandlerText
{
public:
    HandlerTextSaveFile(const std::string &pathname, const std::string &filename)
        : _pathname(pathname), _filename(filename)
    {
        if (std::filesystem::exists(_pathname))
            return;
        // 递归创建目录结构
        try
        {
            std::filesystem::create_directories(_pathname);
        }
        catch (const std::filesystem::filesystem_error &e)
        {
            std::cerr << e.what() << std::endl;
            exit(1);
        }
    }
    virtual void Excute(const std::string &msg)
    {
        if (Stat())
        {
            std::cout << "step 2:文本保存到文件" << std::endl;
            std::string file = _pathname + _filename;
            std::ofstream append_file(file, std::ios::app);
            if (!append_file.is_open())
            {
                EXIT_ERROR("open file");
            }
            // 写入文件，追加写入
            append_file << msg;
            append_file.close();
        }
        else
        {
            std::cout << "step 2:文本保存到文件(已禁用)" << std::endl;
        }
        if (_next)
        {
            _next->Excute(msg);
        }
        else
        {
            std::cout << "责任链终止在HandlerTextSaveFile" << std::endl;
        }
    }

private:
    std::string _pathname;
    std::string _filename;
};

const int maxLineSize = 5;

// 备份（改名，改名成文件名拼接上时间戳），打包文件，删除源文件
class HandlerTextBackupFile : public HandlerText
{
private:
    bool LineOverFlow()
    {
        std::string file = _pathname + _filename;
        std::ifstream read_file(file);
        if (!read_file.is_open())
        {
            EXIT_ERROR("open file");
        }
        std::string line;
        int lineCount = 0;
        while (std::getline(read_file, line))
        {
            lineCount++;
        }
        read_file.close();
        if (lineCount > _maxLineSize)
        {
            return true;
        }
        return false;
    }

    // 备份
    void Backup()
    {
        std::string file = _pathname + _filename;
        // 新文件名
        std::string backup_filename = _filename + "." + std::to_string((int)time(nullptr));
        _backup_filename = backup_filename;
        std::string backup_file = _pathname + backup_filename;
        // 重命名
        std::filesystem::rename(file, backup_file);
    }

    // 打包并删除源文件
    void PackAndDelete()
    {
        std::string pack_filename = _backup_filename + ".tgz";
        pid_t pid = fork();
        if (pid == 0)
        {
            // 改变子进程工作路径至_pathname用C++方式
            std::filesystem::current_path(_pathname);
            // 子进程程序替换执行tar命令，打包文件
            execlp("tar", "tar", "-czf", pack_filename.c_str(), _backup_filename.c_str(), nullptr);
            exit(1);
        }
        int status;
        int ret = waitpid(pid, &status, 0);
        if (ret < 0)
        {
            EXIT_ERROR("waitpid");
        }
        else
        {
            // 子进程正常退出，且退出码为0，删除源文件
            if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
            {
                std::filesystem::path file = _pathname + _backup_filename;
                std::filesystem::remove(file);
            }
        }
    }

public:
    HandlerTextBackupFile(const std::string &pathname, const std::string &filename)
        : _pathname(pathname), _filename(filename), _maxLineSize(maxLineSize)
    {
    }

    virtual void Excute(const std::string &msg)
    {
        if (Stat())
        {
            std::cout << "step 3:文本备份" << std::endl;
            // 备份
            if (LineOverFlow())
            {
                std::cout << "超过最大行数限制，备份" << std::endl;
                Backup();
                std::cout << "备份文件名：" << _backup_filename << std::endl;
                std::cout << "打包并删除备份文件" << std::endl;
                PackAndDelete();
            }
        }
        else
        {
            std::cout << "step 3:文本备份(已禁用)" << std::endl;
        }
        if (_next)
        {
            _next->Excute(msg);
        }
        else
        {
            std::cout << "责任链终止在HandlerTextBackupFile" << std::endl;
        }
    }

private:
    std::string _pathname;
    std::string _filename;
    std::string _backup_filename;
    int _maxLineSize;
};

class HandlerEntry
{
private:
    void StatSet(bool e1, bool e2, bool e3)
    {
        e1 ? _format->Enable() : _format->Disable();
        e2 ? _save->Enable() : _save->Disable();
        e3 ? _backup->Enable() : _backup->Disable();
    }

public:
    HandlerEntry(bool e1, bool e2, bool e3)
    {
        _format = std::make_shared<HandlerTextFormat>(PATH_DEFAULT, FILE_DEFAULT);
        _save = std::make_shared<HandlerTextSaveFile>(PATH_DEFAULT, FILE_DEFAULT);
        _backup = std::make_shared<HandlerTextBackupFile>(PATH_DEFAULT, FILE_DEFAULT);
        _format->SetNext(_save);
        _save->SetNext(_backup);
        StatSet(e1, e2, e3);
    }
    void Run(const std::string &msg)
    {
        _format->Excute(msg);
    }

private:
    std::shared_ptr<HandlerTextFormat> _format;
    std::shared_ptr<HandlerTextSaveFile> _save;
    std::shared_ptr<HandlerTextBackupFile> _backup;
};

#endif // CHAIN_OF_RESP_HPP